Scenario 1: Random Scatter
To begin, pursue the point of view that structure in the data is indicated by departures from a uniform scatter of palindromes across the DNA.
Of course, a random uniform scatter does that mean that palindromes will be equally spaced as milestones on a freeway. There will be some gaps on the DNA where no palindromes occur, and there will be some clumping together of palindromes.
To look for structure examine the locations of the palindromes, the spacing between palindromes, and the counts of palindromes in non overlapping regions of the DNA. One starting place might be to see first how random scatter looks by using a computer to simulate it.
A computer can simulate 296 palindrome sites chosen at random along a DNA sequence of 229,354 bases using a pseudo random number generator. When this is done several times, by making seller sets of simulated palindrome locations, then the real data can be compared to the simulated data.
set.seed(0)
color <- 'red'
# Generate 3 samples from the uniform distribution with the same size and bounds as our data
samples=list(sort(runif(n, min=0, max=N)), sort(runif(n, min=0, max=N)), sort(runif(n, min=0, max=N)))
# Dot plot of locations of palindromes in original data and uniform scatter
title1 <- 'Locations of Palindromes'
title2 <- c(title1,'(Simulated)')
x.axis <- 'Base Pair'
symbol <- 3
stripchart(locations, pch=symbol, col=color, main=title1, xlab=x.axis)

for (sample in samples) {
stripchart(sample, pch=symbol, main=title2, xlab=x.axis)
}



# Additional dot plot of locations of palindromes in original data and uniform scatter
dotchart(locations, color=color, main=title1, xlab=x.axis)

for (sample in samples) {
dotchart(sample, main=title2, xlab=x.axis)
}



# Histogram of locations of palindromes in original data and uniform scatter
bins <- 35
hist(locations, col=color, breaks=bins, main=title1, xlab=x.axis)

for (sample in samples) {
hist(sample, breaks=bins, main=title2, xlab=x.axis)
}



# Scatterplot of spacing between consecutive palindromes
title1 <- 'Spacing between Consecutive Palindromes'
title2 <- c(title1,'(Simulated)')
x.axis <- 'Base Pair Location'
y.axis <- 'Distance (Base Pairs) from Previous Palindrome'
y.range <- c(0,5000)
plot(locations[-1], diff(locations), col=color, ylim=y.range, main=title1, xlab=x.axis, ylab=y.axis)

for (sample in samples) {
plot(sample[-1], diff(sample), ylim=y.range, main=title2, xlab=x.axis, ylab=y.axis)
}



# Histogram of counts of palindromes in non-overlapping regions in original data and uniform scatter
interval.length <- 2500
title1 <- paste('Number of Palindromes in Non-Overlapping Regions of Length', interval.length)
title2 <- c(title1,'(Simulated)')
x.axis <- 'Number of Palindromes'
bins <- seq(0,20,1)
hist(as.vector(table(cut(locations, breaks=seq(0,N,interval.length), include.lowest=TRUE))), breaks=bins, col=color, main=title1, xlab=x.axis)

for (sample in samples) {
hist(as.vector(table(cut(sample, breaks=seq(0,N,interval.length), include.lowest=TRUE))), breaks=bins, main=title2, xlab=x.axis)
}



Scenario 2: Locations and Spacings
Use graphical methods to examine the spacings between consecutive palindromes and sum of consecutive pairs, triplets, etc, spacings. Compare what you find to what you would expect to find in a random scatter. Also, use graphical methods to compare locations of the palindromes.
# Chi-square Goodness of Fit Test
# Case 1: k(number of sub-intervals)=20
k <- 20
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=19)
p_value <- pchisq(chi_2, df=19, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 20 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 20 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 17.9189189189189"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.527860332119311"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 20 sub-intervals)')

# Case 2: k(number of sub-intervals)=30
k <- 30
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=29)
p_value <- pchisq(chi_2, df=29, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 30 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 30 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 40.6891891891892"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.0732835870345071"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 30 sub-intervals)')

# Case 3: k(number of sub-intervals)=60
k <- 60
locations.expected <- n/k
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
locations.observed <- as.vector(tab)
chi_2 <- sum((locations.observed - locations.expected)^2/locations.expected)
chi2_compare <- qchisq(p=0.95, df=59)
p_value <- pchisq(chi_2, df=59, lower.tail=FALSE)
print(cat('\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 60 sub-intervals) against uniform distribution\n'))
When conducting chi_square Goodness of fit test comparing locations(divided in 60 sub-intervals) against uniform distribution
NULL
print(paste('The value of chi_square statistic is', chi_2))
[1] "The value of chi_square statistic is 79"
print(paste('The p_value is', p_value))
[1] "The p_value is 0.0421403871302519"
## Visualization of the Residual
Residuals <- (locations.observed - locations.expected) / sqrt(locations.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 60 sub-intervals)')

# Histogram of locations of palindromes in original data and uniform scatter
sample <- runif(n, min=0, max=N)
title <- 'Locations of Palindromes (Original vs. Simulated)'
x.axis <- 'Base Pair'
bins <- 35
hist(locations, breaks=bins, probability=TRUE, col=rgb(1,0,0,0.5), main=title, xlab=x.axis)
lines(density(locations, adjust=2), col=2)
hist(uniform, breaks=bins, probability=TRUE, col=rgb(0,0,1,0.5), add=TRUE)
lines(density(uniform, adjust=2), col=4)
legend('topright', legend=c('Original', 'Uniform'), lty=c(1,1), col=c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

Inference: Null Hypothesis: Locations are distributed uniformly. Conclusion: Since p-value of this chi-square test is smaller than 0.05, we fail to reject the null hypothesis. It indicates that deviations as large as ours are not so likely. Hence, we conclude that it appears that uniform is not a reasonable initial model. Residual Conclusion: Since the value of the standardized residual is larger than 3, the probability model of a uniform distribution is lack of fit.
Spacings We performed the tests three times over three different lengths of sub-intervals.
# Single Palindrome Spacing
locations.sorted = sort(locations, decreasing = FALSE)
distance.single <- abs(locations.sorted[-1]-locations.sorted[-length(locations.sorted)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.single, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive palindrome Spacings Distribution Comparison", xlab = "Distance between Consecutive Palindromes", ylim = c(0,0.001))
lines(density(distance.single, adjust = 2), col = rgb(1,0,0,0.5))
Expo <- rexp(n-1, rate = 1/mean(distance.single))
hist(Expo, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Expo, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 4200, y = 0.0009, legend = c("Sample", "Exponential"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-square Goodness of Fit Test
# Case 1: Divided in 7 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
lambda <- 1/mean(distance.single)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(0,0.05, 0.1, 0.3, 0.5, 0.7, 0.9,1)))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks=spacings.intervals, include.lowest=TRUE)))
contingency_7 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_7
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=5)
p_value <- pchisq(chi_2, df=5, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 7 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 7 sub-intervals is 6.42447875347949e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 7 bins)')

# Case 2: Divided in 10 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.1))))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_10 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_10
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=8)
p_value <- pchisq(chi_2, df=8, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 10 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 10 sub-intervals is 0.000218981752365422"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 10 bins)')

# Case 3: Divided in 20 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.single, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.05))))
spacings.expected <- (n-1)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.single, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_20 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_20
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=18)
p_value <- pchisq(chi_2, df=18, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 20 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 20 sub-intervals is 0.0117020696134169"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Palindrome locations', main='Plot of Standardized Residual for Locations (divided in 20 bins)')

# Consecutive Pairs
locations.sorted <- sort(locations, decreasing = FALSE)
locations.pairs <- locations.sorted[-length(locations.sorted)]
distance.pairs <- abs(locations.sorted[-1][-1]-locations.pairs[-length(locations.pairs)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.pairs, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive Pairs Spacings Distribution Comparison", xlab = "Distance between Consecutive Pairs of Palindromes Locations", ylim = c(0,0.001))
lines(density(distance.pairs, adjust = 2), col = rgb(1,0,0,0.5))
Expo <- rexp(n-2, rate = 1/mean(distance.pairs))
hist(Expo, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Expo, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 4200, y = 0.0005, legend = c("Sample", "Exponential"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

# Chi-square Goodness of Fit Test
# Case 1: Divided in 7 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
lambda <- 1/mean(distance.pairs)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(0,0.05, 0.1, 0.3, 0.5, 0.7, 0.9,1)))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_7 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_7
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=5)
p_value <- pchisq(chi_2, df=5, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 7 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 7 sub-intervals is 4.0192806354887e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Spacings between Palindrome Pairs', main='Plot of Standardized Residual for Locations (divided in 7 bins)')

# Case 2: Divided in 10 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.1))))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_10 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_10
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=8)
p_value <- pchisq(chi_2, df=8, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 10 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 10 sub-intervals is 1.68753795541538e-05"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type='h', ylab='Standardized Residuals', xlab='Spacings between Palindrome Pairs', main='Plot of Standardized Residual for Locations (divided in 10 bins)')

# Case 3: Divided in 20 intervals
# Construct expected number of intervals
spacings.observed <- sort(distance.pairs, decreasing = FALSE)
spacings.intervals <- as.numeric(quantile(spacings.observed, probs = c(seq(0,1, by = 0.05))))
spacings.expected <- (n-2)*(exp(-lambda*spacings.intervals[-length(spacings.intervals)])-exp(-lambda*spacings.intervals[-1]))
spacings.expected[length(spacings.expected)] <- n-sum(spacings.expected[1:length(spacings.expected)-1])
spacings.observed <- as.numeric(table(cut(distance.pairs, breaks = spacings.intervals, include.lowest = TRUE)))
contingency_20 <- data.frame(spacings.intervals[-1],spacings.observed,spacings.expected)
contingency_20
chi_2 <- sum((spacings.observed - spacings.expected)^2/spacings.expected)
chi2_compare <- qchisq(p=0.95, df=18)
p_value <- pchisq(chi_2, df=18, lower.tail=FALSE)
print(paste('The p_value when the distance is splited into 20 sub-intervals is', p_value))
[1] "The p_value when the distance is splited into 20 sub-intervals is 0.000159225622786541"
## Visualization of the Residual
Residuals <- (spacings.observed - spacings.expected) / sqrt(spacings.expected)
plot(Residuals, type = 'h', ylab = "Standardized Residuals", xlab = "Spacings between Palindrome Pairs", main = "Plot of Standardized Residual for Locations (divided in 20 bins)")

# Consecutive Triplets
locations.sorted <- sort(locations, decreasing = FALSE)
locations.triplets <- locations.sorted[-length(locations.sorted)]
locations.triplets <- locations.triplets[-length(locations.triplets)]
distance.triplets <- abs(locations.sorted[-1][-1][-1]-locations.triplets[-length(locations.triplets)])
# Histogram of spacings of palindromes in original data and exponential distribution
hist(distance.triplets, breaks= 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Consecutive Triplets Spacings Distribution Comparison", xlab = "Distance between Consecutive Palindromes Triplets", ylim = c(0,0.0004))
lines(density(distance.triplets, adjust = 2), col = rgb(1,0,0,0.5))
Gam <- rgamma(n-2, 2, rate = 1/mean(distance.pairs))
hist(Gam, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Gam, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 5000, y = 0.0003, legend = c("Sample", "Gamma"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))

Scenario 3: Counts
Use graphical methods and more formal statistical tests to examine the counts of palindromes in various regions of the DNA. Split the DNA into nonoverlapping regions of equal length to compare the number of palindomres in an interval to the number of that you would expect from uniform random scatter. The counts for shorter regions will be more variable than those for logner regions. Also, consider classifying the regions according to the number of counts.
k <- 50
tab <- table(cut(locations, breaks = seq(0, N, length.out = k+1), include.lowest = TRUE))
counts.obs <- as.vector(tab)
a <- table(cut(counts.obs, breaks = seq(min(counts.obs), max(counts.obs), length.out = k+1), include.lowest = TRUE))
# Histogram of counts of palindromes in original data and poisson distribution
hist(counts.obs, breaks = 15, col = rgb(1,0,0,0.5), probability = TRUE, main = "Counts Distribution Comparison (50 Sub-intervals)", xlab = "Number of Palindromes Sites Inside an Interval", ylim = c(0,0.2))
lines(density(counts.obs, adjust = 2), col = rgb(1,0,0,0.5))
Pois <- rpois(n, lambda = mean(counts.obs))
hist(Pois, breaks = 15, col = rgb(0,0,1,0.5), probability = TRUE, add = TRUE)
lines(density(Pois, adjust = 2), col = rgb(0,0,1,0.5))
legend(x = 12, y = 0.15, legend = c("sample", "Poisson"), lty = c(1,1), col = c(rgb(1,0,0,0.5), rgb(0,0,1,0.5)))
# Chi-Square Testing
# Construct palindrome count number
palindrome.count <- c("0,1,2", "3","4","5","6","7","8+")
# Construct observed number of intervals
intervals.observed <- c(8, 9, 13, 10, 8, 8, 5)
# Construct expected number of intervals
expected <- c()
lambda <- n/k
for (i in c(0:17)){
expect <- k* exp(-lambda)* lambda**i /factorial(i)
expected <- c(expected, expect)
}
sum <- 0
for (j in c(9:17)){
sum <- sum+expected[j]
}
intervals.expected <- c(expected[1]+expected[2]+expected[3],expected[4],expected[5],expected[6],expected[7],expected[8],sum)
# Create contingency table
b <- data.frame(palindrome.count,intervals.observed,intervals.expected)
b
chi_2 <- sum((intervals.observed - intervals.expected)^2/intervals.expected)
chi2_compare <- qchisq(p = 0.95, df = 7)
p_value <- pchisq(chi_2, df = 7, lower.tail = FALSE)
print(cat("\nWhen conducting chi_square Goodness of fit test comparing locations(divided in 500 sub-intervals) against uniform distribution\n"))
print(paste("The value of chi_square statistic is", chi_2))
print(paste("The p_value is", p_value))
=======
distance.triplets
locations
>>>>>>> 7c6d91162e942248a72b7376e3ba96a0cbefb500
>>>>>>> 2503966c4effba0274039c0ceaf32f9c4bc4a90e
Gam <- rgamma(n-2, 2, rate = 2/mean(distance.triplets)) ## Scenario 4: The Biggest Cluster Does the interval with the greatest number of palindromes indicate a potential origin of replication? Be careful in making your intervals, for any small, but significant deviations from random scatter, such as a tight cluster of a few palindromes, could easily go undetected if the regions examined are too large. Also, if the regions are too small, a cluster of palindromes may be split between adjacent interavls and not appear as a high-count interval.
final <- array(dim=c(500,1))
interval_length <- array(dim=c(500,1))
lamda <- array(dim=c(500,1))
for (k in 20:100){
tab <- table(cut(locations, breaks=seq(0, N, length.out=k+1), include.lowest=TRUE))
head(tab,10)
tab<-as.vector(tab)
lamda[k,] <-sum(tab)/k
threshold <-max(tab)
result <- 0
interval_length[k,] <- N/k
for (i in 0:(threshold-1)){
result <- result+((lamda[k]^i)*exp(-lamda[k])/factorial(i))
}
final[k,] <- 1-result^k
}
result <- data.frame(lamda,interval_length,final)
# Display Table containing the probability of a Poisson Distribution having e greatest number of hits at least k for each sub-interval divisions
result[c(20:100),]
LS0tCnRpdGxlOiAnQ0FTRSBTVFVEWSAzOiBTRUFSQ0ggRk9SIFRIRSBVTlVTVUFMIENMVVNURVIgSU4gVEhFIFBBTElORFJPTUVTJwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKIyMgUXVlc3Rpb24KSW4gdGhpcyBwYXBlciwgd2Ugd2lsbCBzZWFyY2ggZm9yIHVudXN1YWwgY2x1c3RlcnMgb2YgY29tcGxlbWVudGFyeSBwYWxpbmRyb21lcy4gVGhlIG92ZXJhcmNoaW5nIHJlc2VhcmNoIHF1ZXN0aW9uIGlzOiDigJxIb3cgZG8gd2UgZmluZCBjbHVzdGVycyBvZiBwYWxpbmRyb21lcz8gSG93IGRvIHdlIGRldGVybWluZSB3aGV0aGVyIGEgY2x1c3RlciBpcyBqdXN0IGEgY2hhbmNlIG9jY3VycmVuY2Ugb3IgYSBwb3RlbnRpYWwgcmVwbGljYXRpb24gc2l0ZT8gQmFzZWQgb24gb3VyIGFuYWx5c2lzLCB3ZSB3aWxsIHRoZW4gcHJvdmlkZSByZWNvbW1lbmRhdGlvbnMgdG8gYmlvbG9naXN0cyB3aG8gYXJlIGFib3V0IHRvIHN0YXJ0IGV4cGVyaW1lbnRhbGx5IHNlYXJjaGluZyBmb3IgdGhlIG9yaWdpbiBvZiByZXBsaWNhdGlvbi4KCgojIyBTZXR1cApgYGB7cn0KbG9jYXRpb25zIDwtIHJlYWQudGFibGUoJ2hjbXYtMjVrZ2puMS0xcmZydGtjLnR4dCcsIGhlYWRlcj1UUlVFKSRsb2NhdGlvbiAgIyBPcmlnaW5hbApoZWFsdGggPC0gcmVhZC5jc3YoJ1JBV19EQVRBLTJpd2N6bm4tMmtyMnh3MC5jc3YnLCBoZWFkZXI9VFJVRSkgICMgQWRkaXRpb25hbAoKTiA8LSAyMjkzNTQgICMgQmFzZSBwYWlycwpuIDwtIDI5NiAgIyBQYWxpbmRyb21lcwpgYGAKCgojIyBTY2VuYXJpbyAxOiBSYW5kb20gU2NhdHRlcgpUbyBiZWdpbiwgcHVyc3VlIHRoZSBwb2ludCBvZiB2aWV3IHRoYXQgc3RydWN0dXJlIGluIHRoZSBkYXRhIGlzIGluZGljYXRlZCBieSBkZXBhcnR1cmVzIGZyb20gYSB1bmlmb3JtIHNjYXR0ZXIgb2YgcGFsaW5kcm9tZXMgYWNyb3NzIHRoZSBETkEuCgoqT2YgY291cnNlLCBhIHJhbmRvbSB1bmlmb3JtIHNjYXR0ZXIgZG9lcyB0aGF0IG1lYW4gdGhhdCBwYWxpbmRyb21lcyB3aWxsIGJlIGVxdWFsbHkgc3BhY2VkIGFzIG1pbGVzdG9uZXMgb24gYSBmcmVld2F5LiBUaGVyZSB3aWxsIGJlIHNvbWUgZ2FwcyBvbiB0aGUgRE5BIHdoZXJlIG5vIHBhbGluZHJvbWVzIG9jY3VyLCBhbmQgdGhlcmUgd2lsbCBiZSBzb21lIGNsdW1waW5nIHRvZ2V0aGVyIG9mIHBhbGluZHJvbWVzLioKClRvIGxvb2sgZm9yIHN0cnVjdHVyZSBleGFtaW5lIHRoZSBsb2NhdGlvbnMgb2YgdGhlIHBhbGluZHJvbWVzLCB0aGUgc3BhY2luZyBiZXR3ZWVuIHBhbGluZHJvbWVzLCBhbmQgdGhlIGNvdW50cyBvZiBwYWxpbmRyb21lcyBpbiBub24gb3ZlcmxhcHBpbmcgcmVnaW9ucyBvZiB0aGUgRE5BLiBPbmUgc3RhcnRpbmcgcGxhY2UgbWlnaHQgYmUgdG8gc2VlIGZpcnN0IGhvdyByYW5kb20gc2NhdHRlciBsb29rcyBieSB1c2luZyBhIGNvbXB1dGVyIHRvIHNpbXVsYXRlIGl0LgoKKkEgY29tcHV0ZXIgY2FuIHNpbXVsYXRlIDI5NiBwYWxpbmRyb21lIHNpdGVzIGNob3NlbiBhdCByYW5kb20gYWxvbmcgYSBETkEgc2VxdWVuY2Ugb2YgMjI5LDM1NCBiYXNlcyB1c2luZyBhIHBzZXVkbyByYW5kb20gbnVtYmVyIGdlbmVyYXRvci4gV2hlbiB0aGlzIGlzIGRvbmUgc2V2ZXJhbCB0aW1lcywgYnkgbWFraW5nIHNlbGxlciBzZXRzIG9mIHNpbXVsYXRlZCBwYWxpbmRyb21lIGxvY2F0aW9ucywgdGhlbiB0aGUgcmVhbCBkYXRhIGNhbiBiZSBjb21wYXJlZCB0byB0aGUgc2ltdWxhdGVkIGRhdGEuKgpgYGB7cn0Kc2V0LnNlZWQoMCkKY29sb3IgPC0gJ3JlZCcKCiMgR2VuZXJhdGUgMyBzYW1wbGVzIGZyb20gdGhlIHVuaWZvcm0gZGlzdHJpYnV0aW9uIHdpdGggdGhlIHNhbWUgc2l6ZSBhbmQgYm91bmRzIGFzIG91ciBkYXRhCnNhbXBsZXM9bGlzdChzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpLCBzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpLCBzb3J0KHJ1bmlmKG4sIG1pbj0wLCBtYXg9TikpKQoKIyBEb3QgcGxvdCBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCnRpdGxlMSA8LSAnTG9jYXRpb25zIG9mIFBhbGluZHJvbWVzJwp0aXRsZTIgPC0gYyh0aXRsZTEsJyhTaW11bGF0ZWQpJykKeC5heGlzIDwtICdCYXNlIFBhaXInCnN5bWJvbCA8LSAzCnN0cmlwY2hhcnQobG9jYXRpb25zLCBwY2g9c3ltYm9sLCBjb2w9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIHN0cmlwY2hhcnQoc2FtcGxlLCBwY2g9c3ltYm9sLCBtYWluPXRpdGxlMiwgeGxhYj14LmF4aXMpCn0KCiMgQWRkaXRpb25hbCBkb3QgcGxvdCBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmRvdGNoYXJ0KGxvY2F0aW9ucywgY29sb3I9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGRvdGNoYXJ0KHNhbXBsZSwgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzKQp9CgojIEhpc3RvZ3JhbSBvZiBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmJpbnMgPC0gMzUKaGlzdChsb2NhdGlvbnMsIGNvbD1jb2xvciwgYnJlYWtzPWJpbnMsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGhpc3Qoc2FtcGxlLCBicmVha3M9YmlucywgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzKQp9CgoKCiMgU2NhdHRlcnBsb3Qgb2Ygc3BhY2luZyBiZXR3ZWVuIGNvbnNlY3V0aXZlIHBhbGluZHJvbWVzCnRpdGxlMSA8LSAnU3BhY2luZyBiZXR3ZWVuIENvbnNlY3V0aXZlIFBhbGluZHJvbWVzJwp0aXRsZTIgPC0gYyh0aXRsZTEsJyhTaW11bGF0ZWQpJykKeC5heGlzIDwtICdCYXNlIFBhaXIgTG9jYXRpb24nCnkuYXhpcyA8LSAnRGlzdGFuY2UgKEJhc2UgUGFpcnMpIGZyb20gUHJldmlvdXMgUGFsaW5kcm9tZScKeS5yYW5nZSA8LSBjKDAsNTAwMCkKcGxvdChsb2NhdGlvbnNbLTFdLCBkaWZmKGxvY2F0aW9ucyksIGNvbD1jb2xvciwgeWxpbT15LnJhbmdlLCBtYWluPXRpdGxlMSwgeGxhYj14LmF4aXMsIHlsYWI9eS5heGlzKQpmb3IgKHNhbXBsZSBpbiBzYW1wbGVzKSB7CiAgcGxvdChzYW1wbGVbLTFdLCBkaWZmKHNhbXBsZSksIHlsaW09eS5yYW5nZSwgbWFpbj10aXRsZTIsIHhsYWI9eC5heGlzLCB5bGFiPXkuYXhpcykKfQoKCgojIEhpc3RvZ3JhbSBvZiBjb3VudHMgb2YgcGFsaW5kcm9tZXMgaW4gbm9uLW92ZXJsYXBwaW5nIHJlZ2lvbnMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgdW5pZm9ybSBzY2F0dGVyCmludGVydmFsLmxlbmd0aCA8LSAyNTAwCnRpdGxlMSA8LSBwYXN0ZSgnTnVtYmVyIG9mIFBhbGluZHJvbWVzIGluIE5vbi1PdmVybGFwcGluZyBSZWdpb25zIG9mIExlbmd0aCcsIGludGVydmFsLmxlbmd0aCkKdGl0bGUyIDwtIGModGl0bGUxLCcoU2ltdWxhdGVkKScpCnguYXhpcyA8LSAnTnVtYmVyIG9mIFBhbGluZHJvbWVzJwpiaW5zIDwtIHNlcSgwLDIwLDEpCmhpc3QoYXMudmVjdG9yKHRhYmxlKGN1dChsb2NhdGlvbnMsIGJyZWFrcz1zZXEoMCxOLGludGVydmFsLmxlbmd0aCksIGluY2x1ZGUubG93ZXN0PVRSVUUpKSksIGJyZWFrcz1iaW5zLCBjb2w9Y29sb3IsIG1haW49dGl0bGUxLCB4bGFiPXguYXhpcykKZm9yIChzYW1wbGUgaW4gc2FtcGxlcykgewogIGhpc3QoYXMudmVjdG9yKHRhYmxlKGN1dChzYW1wbGUsIGJyZWFrcz1zZXEoMCxOLGludGVydmFsLmxlbmd0aCksIGluY2x1ZGUubG93ZXN0PVRSVUUpKSksIGJyZWFrcz1iaW5zLCBtYWluPXRpdGxlMiwgeGxhYj14LmF4aXMpCn0KYGBgCgoKIyMgU2NlbmFyaW8gMjogTG9jYXRpb25zIGFuZCBTcGFjaW5ncwpVc2UgZ3JhcGhpY2FsIG1ldGhvZHMgdG8gZXhhbWluZSB0aGUgc3BhY2luZ3MgYmV0d2VlbiBjb25zZWN1dGl2ZSBwYWxpbmRyb21lcyBhbmQgc3VtIG9mIGNvbnNlY3V0aXZlIHBhaXJzLCB0cmlwbGV0cywgZXRjLCBzcGFjaW5ncy4gQ29tcGFyZSB3aGF0IHlvdSBmaW5kIHRvIHdoYXQgeW91IHdvdWxkIGV4cGVjdCB0byBmaW5kIGluIGEgcmFuZG9tIHNjYXR0ZXIuIEFsc28sIHVzZSBncmFwaGljYWwgbWV0aG9kcyB0byBjb21wYXJlIGxvY2F0aW9ucyBvZiB0aGUgcGFsaW5kcm9tZXMuCmBgYHtyfQojIENoaS1zcXVhcmUgR29vZG5lc3Mgb2YgRml0IFRlc3QKIyBDYXNlIDE6IGsobnVtYmVyIG9mIHN1Yi1pbnRlcnZhbHMpPTIwCmsgPC0gMjAKbG9jYXRpb25zLmV4cGVjdGVkIDwtIG4vawp0YWIgPC0gdGFibGUoY3V0KGxvY2F0aW9ucywgYnJlYWtzPXNlcSgwLCBOLCBsZW5ndGgub3V0PWsrMSksIGluY2x1ZGUubG93ZXN0PVRSVUUpKQpsb2NhdGlvbnMub2JzZXJ2ZWQgPC0gYXMudmVjdG9yKHRhYikKY2hpXzIgPC0gc3VtKChsb2NhdGlvbnMub2JzZXJ2ZWQgLSBsb2NhdGlvbnMuZXhwZWN0ZWQpXjIvbG9jYXRpb25zLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHA9MC45NSwgZGY9MTkpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZj0xOSwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQoY2F0KCdcbldoZW4gY29uZHVjdGluZyBjaGlfc3F1YXJlIEdvb2RuZXNzIG9mIGZpdCB0ZXN0IGNvbXBhcmluZyBsb2NhdGlvbnMoZGl2aWRlZCBpbiAyMCBzdWItaW50ZXJ2YWxzKSBhZ2FpbnN0IHVuaWZvcm0gZGlzdHJpYnV0aW9uXG4nKSkKcHJpbnQocGFzdGUoJ1RoZSB2YWx1ZSBvZiBjaGlfc3F1YXJlIHN0YXRpc3RpYyBpcycsIGNoaV8yKSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIGlzJywgcF92YWx1ZSkpCgojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKGxvY2F0aW9ucy5vYnNlcnZlZCAtIGxvY2F0aW9ucy5leHBlY3RlZCkgLyBzcXJ0KGxvY2F0aW9ucy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGU9J2gnLCB5bGFiPSdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgeGxhYj0nUGFsaW5kcm9tZSBsb2NhdGlvbnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDIwIHN1Yi1pbnRlcnZhbHMpJykKCiMgQ2FzZSAyOiBrKG51bWJlciBvZiBzdWItaW50ZXJ2YWxzKT0zMAprIDwtIDMwCmxvY2F0aW9ucy5leHBlY3RlZCA8LSBuL2sKdGFiIDwtIHRhYmxlKGN1dChsb2NhdGlvbnMsIGJyZWFrcz1zZXEoMCwgTiwgbGVuZ3RoLm91dD1rKzEpLCBpbmNsdWRlLmxvd2VzdD1UUlVFKSkKbG9jYXRpb25zLm9ic2VydmVkIDwtIGFzLnZlY3Rvcih0YWIpCmNoaV8yIDwtIHN1bSgobG9jYXRpb25zLm9ic2VydmVkIC0gbG9jYXRpb25zLmV4cGVjdGVkKV4yL2xvY2F0aW9ucy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwPTAuOTUsIGRmPTI5KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9MjksIGxvd2VyLnRhaWw9RkFMU0UpCnByaW50KGNhdCgnXG5XaGVuIGNvbmR1Y3RpbmcgY2hpX3NxdWFyZSBHb29kbmVzcyBvZiBmaXQgdGVzdCBjb21wYXJpbmcgbG9jYXRpb25zKGRpdmlkZWQgaW4gMzAgc3ViLWludGVydmFscykgYWdhaW5zdCB1bmlmb3JtIGRpc3RyaWJ1dGlvblxuJykpCnByaW50KHBhc3RlKCdUaGUgdmFsdWUgb2YgY2hpX3NxdWFyZSBzdGF0aXN0aWMgaXMnLCBjaGlfMikpCnByaW50KHBhc3RlKCdUaGUgcF92YWx1ZSBpcycsIHBfdmFsdWUpKQoKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChsb2NhdGlvbnMub2JzZXJ2ZWQgLSBsb2NhdGlvbnMuZXhwZWN0ZWQpIC8gc3FydChsb2NhdGlvbnMuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1BhbGluZHJvbWUgbG9jYXRpb25zJywgbWFpbj0nUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIExvY2F0aW9ucyAoZGl2aWRlZCBpbiAzMCBzdWItaW50ZXJ2YWxzKScpCgojIENhc2UgMzogayhudW1iZXIgb2Ygc3ViLWludGVydmFscyk9NjAKayA8LSA2MApsb2NhdGlvbnMuZXhwZWN0ZWQgPC0gbi9rCnRhYiA8LSB0YWJsZShjdXQobG9jYXRpb25zLCBicmVha3M9c2VxKDAsIE4sIGxlbmd0aC5vdXQ9aysxKSwgaW5jbHVkZS5sb3dlc3Q9VFJVRSkpCmxvY2F0aW9ucy5vYnNlcnZlZCA8LSBhcy52ZWN0b3IodGFiKQpjaGlfMiA8LSBzdW0oKGxvY2F0aW9ucy5vYnNlcnZlZCAtIGxvY2F0aW9ucy5leHBlY3RlZCleMi9sb2NhdGlvbnMuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj01OSkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmPTU5LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChjYXQoJ1xuV2hlbiBjb25kdWN0aW5nIGNoaV9zcXVhcmUgR29vZG5lc3Mgb2YgZml0IHRlc3QgY29tcGFyaW5nIGxvY2F0aW9ucyhkaXZpZGVkIGluIDYwIHN1Yi1pbnRlcnZhbHMpIGFnYWluc3QgdW5pZm9ybSBkaXN0cmlidXRpb25cbicpKQpwcmludChwYXN0ZSgnVGhlIHZhbHVlIG9mIGNoaV9zcXVhcmUgc3RhdGlzdGljIGlzJywgY2hpXzIpKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgaXMnLCBwX3ZhbHVlKSkKCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAobG9jYXRpb25zLm9ic2VydmVkIC0gbG9jYXRpb25zLmV4cGVjdGVkKSAvIHNxcnQobG9jYXRpb25zLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdQYWxpbmRyb21lIGxvY2F0aW9ucycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNjAgc3ViLWludGVydmFscyknKQoKIyBIaXN0b2dyYW0gb2YgbG9jYXRpb25zIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIHVuaWZvcm0gc2NhdHRlcgpzYW1wbGUgPC0gcnVuaWYobiwgbWluPTAsIG1heD1OKQp0aXRsZSA8LSAnTG9jYXRpb25zIG9mIFBhbGluZHJvbWVzIChPcmlnaW5hbCB2cy4gU2ltdWxhdGVkKScKeC5heGlzIDwtICdCYXNlIFBhaXInCmJpbnMgPC0gMzUKaGlzdChsb2NhdGlvbnMsIGJyZWFrcz1iaW5zLCBwcm9iYWJpbGl0eT1UUlVFLCBjb2w9cmdiKDEsMCwwLDAuNSksIG1haW49dGl0bGUsIHhsYWI9eC5heGlzKQpsaW5lcyhkZW5zaXR5KGxvY2F0aW9ucywgYWRqdXN0PTIpLCBjb2w9MikKaGlzdCh1bmlmb3JtLCBicmVha3M9YmlucywgcHJvYmFiaWxpdHk9VFJVRSwgY29sPXJnYigwLDAsMSwwLjUpLCBhZGQ9VFJVRSkKbGluZXMoZGVuc2l0eSh1bmlmb3JtLCBhZGp1c3Q9MiksIGNvbD00KQpsZWdlbmQoJ3RvcHJpZ2h0JywgbGVnZW5kPWMoJ09yaWdpbmFsJywgJ1VuaWZvcm0nKSwgbHR5PWMoMSwxKSwgY29sPWMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKYGBgCkluZmVyZW5jZToKTnVsbCBIeXBvdGhlc2lzOiBMb2NhdGlvbnMgYXJlIGRpc3RyaWJ1dGVkIHVuaWZvcm1seS4KQ29uY2x1c2lvbjogU2luY2UgcC12YWx1ZSBvZiB0aGlzIGNoaS1zcXVhcmUgdGVzdCBpcyBzbWFsbGVyIHRoYW4gMC4wNSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gSXQgaW5kaWNhdGVzIHRoYXQgZGV2aWF0aW9ucyBhcyBsYXJnZSBhcyBvdXJzIGFyZSBub3Qgc28gbGlrZWx5LiBIZW5jZSwgd2UgY29uY2x1ZGUgdGhhdCBpdCBhcHBlYXJzIHRoYXQgdW5pZm9ybSBpcyBub3QgYSByZWFzb25hYmxlIGluaXRpYWwgbW9kZWwuIApSZXNpZHVhbCBDb25jbHVzaW9uOgpTaW5jZSB0aGUgdmFsdWUgb2YgdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbCBpcyBsYXJnZXIgdGhhbiAzLCB0aGUgcHJvYmFiaWxpdHkgbW9kZWwgb2YgYSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBpcyBsYWNrIG9mIGZpdC4KClNwYWNpbmdzCldlIHBlcmZvcm1lZCB0aGUgdGVzdHMgdGhyZWUgdGltZXMgb3ZlciB0aHJlZSBkaWZmZXJlbnQgbGVuZ3RocyBvZiBzdWItaW50ZXJ2YWxzLgpgYGB7cn0KIyBTaW5nbGUgUGFsaW5kcm9tZSBTcGFjaW5nCmxvY2F0aW9ucy5zb3J0ZWQgPSBzb3J0KGxvY2F0aW9ucywgZGVjcmVhc2luZyA9IEZBTFNFKQpkaXN0YW5jZS5zaW5nbGUgPC0gYWJzKGxvY2F0aW9ucy5zb3J0ZWRbLTFdLWxvY2F0aW9ucy5zb3J0ZWRbLWxlbmd0aChsb2NhdGlvbnMuc29ydGVkKV0pCgojIEhpc3RvZ3JhbSBvZiBzcGFjaW5ncyBvZiBwYWxpbmRyb21lcyBpbiBvcmlnaW5hbCBkYXRhIGFuZCBleHBvbmVudGlhbCBkaXN0cmlidXRpb24KaGlzdChkaXN0YW5jZS5zaW5nbGUsIGJyZWFrcz0gMTUsIGNvbCA9IHJnYigxLDAsMCwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiQ29uc2VjdXRpdmUgcGFsaW5kcm9tZSBTcGFjaW5ncyBEaXN0cmlidXRpb24gQ29tcGFyaXNvbiIsIHhsYWIgPSAiRGlzdGFuY2UgYmV0d2VlbiBDb25zZWN1dGl2ZSBQYWxpbmRyb21lcyIsIHlsaW0gPSBjKDAsMC4wMDEpKQpsaW5lcyhkZW5zaXR5KGRpc3RhbmNlLnNpbmdsZSwgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigxLDAsMCwwLjUpKQpFeHBvIDwtIHJleHAobi0xLCByYXRlID0gMS9tZWFuKGRpc3RhbmNlLnNpbmdsZSkpCmhpc3QoRXhwbywgYnJlYWtzID0gMTUsIGNvbCA9IHJnYigwLDAsMSwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIGFkZCA9IFRSVUUpCmxpbmVzKGRlbnNpdHkoRXhwbywgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigwLDAsMSwwLjUpKQpsZWdlbmQoeCA9IDQyMDAsIHkgPSAwLjAwMDksIGxlZ2VuZCA9IGMoIlNhbXBsZSIsICJFeHBvbmVudGlhbCIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxdWFyZSBHb29kbmVzcyBvZiBGaXQgVGVzdAojIENhc2UgMTogRGl2aWRlZCBpbiA3IGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2Uuc2luZ2xlLCBkZWNyZWFzaW5nID0gRkFMU0UpCmxhbWJkYSA8LSAxL21lYW4oZGlzdGFuY2Uuc2luZ2xlKQpzcGFjaW5ncy5pbnRlcnZhbHMgPC0gYXMubnVtZXJpYyhxdWFudGlsZShzcGFjaW5ncy5vYnNlcnZlZCwgcHJvYnMgPSBjKDAsMC4wNSwgMC4xLCAwLjMsIDAuNSwgMC43LCAwLjksMSkpKQoKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMSkqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5zaW5nbGUsIGJyZWFrcz1zcGFjaW5ncy5pbnRlcnZhbHMsIGluY2x1ZGUubG93ZXN0PVRSVUUpKSkKY29udGluZ2VuY3lfNyA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzcKCmNoaV8yIDwtIHN1bSgoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCleMi9zcGFjaW5ncy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwPTAuOTUsIGRmPTUpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZj01LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDcgc3ViLWludGVydmFscyBpcycsIHBfdmFsdWUpKQojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpIC8gc3FydChzcGFjaW5ncy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGU9J2gnLCB5bGFiPSdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgeGxhYj0nUGFsaW5kcm9tZSBsb2NhdGlvbnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDcgYmlucyknKQoKIyBDYXNlIDI6IERpdmlkZWQgaW4gMTAgaW50ZXJ2YWxzCiMgQ29uc3RydWN0IGV4cGVjdGVkIG51bWJlciBvZiBpbnRlcnZhbHMKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gc29ydChkaXN0YW5jZS5zaW5nbGUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYyhzZXEoMCwxLCBieSA9IDAuMSkpKSkKCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTEpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2Uuc2luZ2xlLCBicmVha3MgPSBzcGFjaW5ncy5pbnRlcnZhbHMsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpKQpjb250aW5nZW5jeV8xMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzEwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj04KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9OCwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byAxMCBzdWItaW50ZXJ2YWxzIGlzJywgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdQYWxpbmRyb21lIGxvY2F0aW9ucycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMTAgYmlucyknKQoKIyBDYXNlIDM6IERpdmlkZWQgaW4gMjAgaW50ZXJ2YWxzCiMgQ29uc3RydWN0IGV4cGVjdGVkIG51bWJlciBvZiBpbnRlcnZhbHMKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gc29ydChkaXN0YW5jZS5zaW5nbGUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYyhzZXEoMCwxLCBieSA9IDAuMDUpKSkpCgpzcGFjaW5ncy5leHBlY3RlZCA8LSAobi0xKSooZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy1sZW5ndGgoc3BhY2luZ3MuaW50ZXJ2YWxzKV0pLWV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stMV0pKQpzcGFjaW5ncy5leHBlY3RlZFtsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpXSA8LSBuLXN1bShzcGFjaW5ncy5leHBlY3RlZFsxOmxlbmd0aChzcGFjaW5ncy5leHBlY3RlZCktMV0pCnNwYWNpbmdzLm9ic2VydmVkIDwtIGFzLm51bWVyaWModGFibGUoY3V0KGRpc3RhbmNlLnNpbmdsZSwgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKCmNvbnRpbmdlbmN5XzIwIDwtIGRhdGEuZnJhbWUoc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSxzcGFjaW5ncy5vYnNlcnZlZCxzcGFjaW5ncy5leHBlY3RlZCkKY29udGluZ2VuY3lfMjAKCmNoaV8yIDwtIHN1bSgoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCleMi9zcGFjaW5ncy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwPTAuOTUsIGRmPTE4KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9MTgsIGxvd2VyLnRhaWw9RkFMU0UpCnByaW50KHBhc3RlKCdUaGUgcF92YWx1ZSB3aGVuIHRoZSBkaXN0YW5jZSBpcyBzcGxpdGVkIGludG8gMjAgc3ViLWludGVydmFscyBpcycsIHBfdmFsdWUpKQojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpIC8gc3FydChzcGFjaW5ncy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGU9J2gnLCB5bGFiPSdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgeGxhYj0nUGFsaW5kcm9tZSBsb2NhdGlvbnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDIwIGJpbnMpJykKYGBgCgpgYGB7cn0KIyBDb25zZWN1dGl2ZSBQYWlycwpsb2NhdGlvbnMuc29ydGVkIDwtICBzb3J0KGxvY2F0aW9ucywgZGVjcmVhc2luZyA9IEZBTFNFKQpsb2NhdGlvbnMucGFpcnMgPC0gbG9jYXRpb25zLnNvcnRlZFstbGVuZ3RoKGxvY2F0aW9ucy5zb3J0ZWQpXQpkaXN0YW5jZS5wYWlycyA8LSBhYnMobG9jYXRpb25zLnNvcnRlZFstMV1bLTFdLWxvY2F0aW9ucy5wYWlyc1stbGVuZ3RoKGxvY2F0aW9ucy5wYWlycyldKQoKIyBIaXN0b2dyYW0gb2Ygc3BhY2luZ3Mgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uCmhpc3QoZGlzdGFuY2UucGFpcnMsIGJyZWFrcz0gMTUsIGNvbCA9IHJnYigxLDAsMCwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiQ29uc2VjdXRpdmUgUGFpcnMgU3BhY2luZ3MgRGlzdHJpYnV0aW9uIENvbXBhcmlzb24iLCB4bGFiID0gIkRpc3RhbmNlIGJldHdlZW4gQ29uc2VjdXRpdmUgUGFpcnMgb2YgUGFsaW5kcm9tZXMgTG9jYXRpb25zIiwgeWxpbSA9IGMoMCwwLjAwMSkpCmxpbmVzKGRlbnNpdHkoZGlzdGFuY2UucGFpcnMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMSwwLDAsMC41KSkKRXhwbyA8LSByZXhwKG4tMiwgcmF0ZSA9IDEvbWVhbihkaXN0YW5jZS5wYWlycykpCmhpc3QoRXhwbywgYnJlYWtzID0gMTUsIGNvbCA9IHJnYigwLDAsMSwwLjUpLCBwcm9iYWJpbGl0eSA9IFRSVUUsIGFkZCA9IFRSVUUpCmxpbmVzKGRlbnNpdHkoRXhwbywgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigwLDAsMSwwLjUpKQpsZWdlbmQoeCA9IDQyMDAsIHkgPSAwLjAwMDUsIGxlZ2VuZCA9IGMoIlNhbXBsZSIsICJFeHBvbmVudGlhbCIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxdWFyZSBHb29kbmVzcyBvZiBGaXQgVGVzdAojIENhc2UgMTogRGl2aWRlZCBpbiA3IGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UucGFpcnMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKbGFtYmRhIDwtIDEvbWVhbihkaXN0YW5jZS5wYWlycykKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYygwLDAuMDUsIDAuMSwgMC4zLCAwLjUsIDAuNywgMC45LDEpKSkKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMikqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5wYWlycywgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKCmNvbnRpbmdlbmN5XzcgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV83CgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj01KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9NSwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byA3IHN1Yi1pbnRlcnZhbHMgaXMnLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1NwYWNpbmdzIGJldHdlZW4gUGFsaW5kcm9tZSBQYWlycycsIG1haW49J1Bsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gNyBiaW5zKScpCgojIENhc2UgMjogRGl2aWRlZCBpbiAxMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnBhaXJzLCBkZWNyZWFzaW5nID0gRkFMU0UpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoc2VxKDAsMSwgYnkgPSAwLjEpKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTIpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCgpjb250aW5nZW5jeV8xMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzEwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj04KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9OCwgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byAxMCBzdWItaW50ZXJ2YWxzIGlzJywgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZT0naCcsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLCB4bGFiPSdTcGFjaW5ncyBiZXR3ZWVuIFBhbGluZHJvbWUgUGFpcnMnLCBtYWluPSdQbG90IG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbCBmb3IgTG9jYXRpb25zIChkaXZpZGVkIGluIDEwIGJpbnMpJykKCiMgQ2FzZSAzOiBEaXZpZGVkIGluIDIwIGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UucGFpcnMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYyhzZXEoMCwxLCBieSA9IDAuMDUpKSkpCnNwYWNpbmdzLmV4cGVjdGVkIDwtIChuLTIpKihleHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLWxlbmd0aChzcGFjaW5ncy5pbnRlcnZhbHMpXSktZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy0xXSkpCnNwYWNpbmdzLmV4cGVjdGVkW2xlbmd0aChzcGFjaW5ncy5leHBlY3RlZCldIDwtIG4tc3VtKHNwYWNpbmdzLmV4cGVjdGVkWzE6bGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKS0xXSkKc3BhY2luZ3Mub2JzZXJ2ZWQgPC0gYXMubnVtZXJpYyh0YWJsZShjdXQoZGlzdGFuY2UucGFpcnMsIGJyZWFrcyA9IHNwYWNpbmdzLmludGVydmFscywgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkpCgpjb250aW5nZW5jeV8yMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzIwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj0xOCkKcF92YWx1ZSA8LSBwY2hpc3EoY2hpXzIsIGRmPTE4LCBsb3dlci50YWlsPUZBTFNFKQpwcmludChwYXN0ZSgnVGhlIHBfdmFsdWUgd2hlbiB0aGUgZGlzdGFuY2UgaXMgc3BsaXRlZCBpbnRvIDIwIHN1Yi1pbnRlcnZhbHMgaXMnLCBwX3ZhbHVlKSkKIyMgVmlzdWFsaXphdGlvbiBvZiB0aGUgUmVzaWR1YWwKUmVzaWR1YWxzIDwtIChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKSAvIHNxcnQoc3BhY2luZ3MuZXhwZWN0ZWQpCgpwbG90KFJlc2lkdWFscywgdHlwZSA9ICdoJywgeWxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgeGxhYiA9ICJTcGFjaW5ncyBiZXR3ZWVuIFBhbGluZHJvbWUgUGFpcnMiLCBtYWluID0gIlBsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMjAgYmlucykiKQpgYGAKCmBgYHtyfQojIENvbnNlY3V0aXZlIFRyaXBsZXRzCmxvY2F0aW9ucy5zb3J0ZWQgPC0gIHNvcnQobG9jYXRpb25zLCBkZWNyZWFzaW5nID0gRkFMU0UpCmxvY2F0aW9ucy50cmlwbGV0cyA8LSBsb2NhdGlvbnMuc29ydGVkWy1sZW5ndGgobG9jYXRpb25zLnNvcnRlZCldCmxvY2F0aW9ucy50cmlwbGV0cyA8LSBsb2NhdGlvbnMudHJpcGxldHNbLWxlbmd0aChsb2NhdGlvbnMudHJpcGxldHMpXQpkaXN0YW5jZS50cmlwbGV0cyA8LSBhYnMobG9jYXRpb25zLnNvcnRlZFstMV1bLTFdWy0xXS1sb2NhdGlvbnMudHJpcGxldHNbLWxlbmd0aChsb2NhdGlvbnMudHJpcGxldHMpXSkKCiMgSGlzdG9ncmFtIG9mIHNwYWNpbmdzIG9mIHBhbGluZHJvbWVzIGluIG9yaWdpbmFsIGRhdGEgYW5kIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbgpoaXN0KGRpc3RhbmNlLnRyaXBsZXRzLCBicmVha3M9IDE1LCBjb2wgPSByZ2IoMSwwLDAsMC41KSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gIkNvbnNlY3V0aXZlIFRyaXBsZXRzIFNwYWNpbmdzIERpc3RyaWJ1dGlvbiBDb21wYXJpc29uIiwgeGxhYiA9ICJEaXN0YW5jZSBiZXR3ZWVuIENvbnNlY3V0aXZlIFBhbGluZHJvbWVzIFRyaXBsZXRzIiwgeWxpbSA9IGMoMCwwLjAwMDQpKQpsaW5lcyhkZW5zaXR5KGRpc3RhbmNlLnRyaXBsZXRzLCBhZGp1c3QgPSAyKSwgY29sID0gcmdiKDEsMCwwLDAuNSkpCkdhbSA8LSByZ2FtbWEobi0yLCAyLCByYXRlID0gMS9tZWFuKGRpc3RhbmNlLnBhaXJzKSkKaGlzdChHYW0sIGJyZWFrcyA9IDE1LCBjb2wgPSByZ2IoMCwwLDEsMC41KSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBhZGQgPSBUUlVFKQpsaW5lcyhkZW5zaXR5KEdhbSwgYWRqdXN0ID0gMiksIGNvbCA9IHJnYigwLDAsMSwwLjUpKQpsZWdlbmQoeCA9IDUwMDAsIHkgPSAwLjAwMDMsIGxlZ2VuZCA9IGMoIlNhbXBsZSIsICJHYW1tYSIpLCBsdHkgPSBjKDEsMSksIGNvbCA9IGMocmdiKDEsMCwwLDAuNSksIHJnYigwLDAsMSwwLjUpKSkKCiMgQ2hpLXNxdWFyZSBHb29kbmVzcyBvZiBGaXQgVGVzdCAoTmVlZCB0byBiZSBjaGFuZ2VkKQojIENhc2UgMTogRGl2aWRlZCBpbiA3IGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UudHJpcGxldHMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKbGFtYmRhIDwtIDIvbWVhbihkaXN0YW5jZS5wYWlycykKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYygwLDAuMDUsIDAuMSwgMC4zLCAwLjUsIDAuNywgMC45LDEpKSkKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMSkqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5wYWlycywgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKY29udGluZ2VuY3lfNyA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzcKCmNoaV8yIDwtIHN1bSgoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCleMi9zcGFjaW5ncy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwID0gMC45NSwgZGYgPSA1KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGYgPSA1LCBsb3dlci50YWlsID0gRkFMU0UpCnByaW50KHBhc3RlKCJUaGUgcF92YWx1ZSB3aGVuIHRoZSBkaXN0YW5jZSBpcyBzcGxpdGVkIGludG8gNyBzdWItaW50ZXJ2YWxzIGlzIiwgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZSA9ICdoJywgeWxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgeGxhYiA9ICJQYWxpbmRyb21lIGxvY2F0aW9ucyIsIG1haW4gPSAiUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIExvY2F0aW9ucyAoZGl2aWRlZCBpbiA3IGJpbnMpIikKCiMgQ2FzZSAyOiBEaXZpZGVkIGluIDEwIGludGVydmFscwojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCnNwYWNpbmdzLm9ic2VydmVkIDwtIHNvcnQoZGlzdGFuY2UucGFpcnMsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc3BhY2luZ3MuaW50ZXJ2YWxzIDwtIGFzLm51bWVyaWMocXVhbnRpbGUoc3BhY2luZ3Mub2JzZXJ2ZWQsIHByb2JzID0gYyhzZXEoMCwxLCBieSA9IDAuMSkpKSkKc3BhY2luZ3MuZXhwZWN0ZWQgPC0gKG4tMSkqKGV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stbGVuZ3RoKHNwYWNpbmdzLmludGVydmFscyldKS1leHAoLWxhbWJkYSpzcGFjaW5ncy5pbnRlcnZhbHNbLTFdKSkKc3BhY2luZ3MuZXhwZWN0ZWRbbGVuZ3RoKHNwYWNpbmdzLmV4cGVjdGVkKV0gPC0gbi1zdW0oc3BhY2luZ3MuZXhwZWN0ZWRbMTpsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpLTFdKQpzcGFjaW5ncy5vYnNlcnZlZCA8LSBhcy5udW1lcmljKHRhYmxlKGN1dChkaXN0YW5jZS5wYWlycywgYnJlYWtzID0gc3BhY2luZ3MuaW50ZXJ2YWxzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKSkKY29udGluZ2VuY3lfMTAgPC0gZGF0YS5mcmFtZShzcGFjaW5ncy5pbnRlcnZhbHNbLTFdLHNwYWNpbmdzLm9ic2VydmVkLHNwYWNpbmdzLmV4cGVjdGVkKQpjb250aW5nZW5jeV8xMAoKY2hpXzIgPC0gc3VtKChzcGFjaW5ncy5vYnNlcnZlZCAtIHNwYWNpbmdzLmV4cGVjdGVkKV4yL3NwYWNpbmdzLmV4cGVjdGVkKQpjaGkyX2NvbXBhcmUgPC0gcWNoaXNxKHAgPSAwLjk1LCBkZiA9IDgpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZiA9IDgsIGxvd2VyLnRhaWwgPSBGQUxTRSkKcHJpbnQocGFzdGUoIlRoZSBwX3ZhbHVlIHdoZW4gdGhlIGRpc3RhbmNlIGlzIHNwbGl0ZWQgaW50byAxMCBzdWItaW50ZXJ2YWxzIGlzIiwgcF92YWx1ZSkpCiMjIFZpc3VhbGl6YXRpb24gb2YgdGhlIFJlc2lkdWFsClJlc2lkdWFscyA8LSAoc3BhY2luZ3Mub2JzZXJ2ZWQgLSBzcGFjaW5ncy5leHBlY3RlZCkgLyBzcXJ0KHNwYWNpbmdzLmV4cGVjdGVkKQpwbG90KFJlc2lkdWFscywgdHlwZSA9ICdoJywgeWxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgeGxhYiA9ICJQYWxpbmRyb21lIGxvY2F0aW9ucyIsIG1haW4gPSAiUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIExvY2F0aW9ucyAoZGl2aWRlZCBpbiAxMCBiaW5zKSIpCgojIENhc2UgMzogRGl2aWRlZCBpbiAyMCBpbnRlcnZhbHMKIyBDb25zdHJ1Y3QgZXhwZWN0ZWQgbnVtYmVyIG9mIGludGVydmFscwpzcGFjaW5ncy5vYnNlcnZlZCA8LSBzb3J0KGRpc3RhbmNlLnBhaXJzLCBkZWNyZWFzaW5nID0gRkFMU0UpCnNwYWNpbmdzLmludGVydmFscyA8LSBhcy5udW1lcmljKHF1YW50aWxlKHNwYWNpbmdzLm9ic2VydmVkLCBwcm9icyA9IGMoc2VxKDAsMSwgYnkgPSAwLjA1KSkpKQpzcGFjaW5ncy5leHBlY3RlZCA8LSAobi0xKSooZXhwKC1sYW1iZGEqc3BhY2luZ3MuaW50ZXJ2YWxzWy1sZW5ndGgoc3BhY2luZ3MuaW50ZXJ2YWxzKV0pLWV4cCgtbGFtYmRhKnNwYWNpbmdzLmludGVydmFsc1stMV0pKQpzcGFjaW5ncy5leHBlY3RlZFtsZW5ndGgoc3BhY2luZ3MuZXhwZWN0ZWQpXSA8LSBuLXN1bShzcGFjaW5ncy5leHBlY3RlZFsxOmxlbmd0aChzcGFjaW5ncy5leHBlY3RlZCktMV0pCnNwYWNpbmdzLm9ic2VydmVkIDwtIGFzLm51bWVyaWModGFibGUoY3V0KGRpc3RhbmNlLnBhaXJzLCBicmVha3MgPSBzcGFjaW5ncy5pbnRlcnZhbHMsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpKQpjb250aW5nZW5jeV8yMCA8LSBkYXRhLmZyYW1lKHNwYWNpbmdzLmludGVydmFsc1stMV0sc3BhY2luZ3Mub2JzZXJ2ZWQsc3BhY2luZ3MuZXhwZWN0ZWQpCmNvbnRpbmdlbmN5XzIwCgpjaGlfMiA8LSBzdW0oKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpXjIvc3BhY2luZ3MuZXhwZWN0ZWQpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocCA9IDAuOTUsIGRmID0gMTgpCnBfdmFsdWUgPC0gcGNoaXNxKGNoaV8yLCBkZiA9IDE4LCBsb3dlci50YWlsID0gRkFMU0UpCnByaW50KHBhc3RlKCJUaGUgcF92YWx1ZSB3aGVuIHRoZSBkaXN0YW5jZSBpcyBzcGxpdGVkIGludG8gMjAgc3ViLWludGVydmFscyBpcyIsIHBfdmFsdWUpKQojIyBWaXN1YWxpemF0aW9uIG9mIHRoZSBSZXNpZHVhbApSZXNpZHVhbHMgPC0gKHNwYWNpbmdzLm9ic2VydmVkIC0gc3BhY2luZ3MuZXhwZWN0ZWQpIC8gc3FydChzcGFjaW5ncy5leHBlY3RlZCkKcGxvdChSZXNpZHVhbHMsIHR5cGUgPSAnaCcsIHlsYWIgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIsIHhsYWIgPSAiUGFsaW5kcm9tZSBsb2NhdGlvbnMiLCBtYWluID0gIlBsb3Qgb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFsIGZvciBMb2NhdGlvbnMgKGRpdmlkZWQgaW4gMjAgYmlucykiKQoKCmBgYAoKIyMgU2NlbmFyaW8gMzogQ291bnRzClVzZSBncmFwaGljYWwgbWV0aG9kcyBhbmQgbW9yZSBmb3JtYWwgc3RhdGlzdGljYWwgdGVzdHMgdG8gZXhhbWluZSB0aGUgY291bnRzIG9mIHBhbGluZHJvbWVzIGluIHZhcmlvdXMgcmVnaW9ucyBvZiB0aGUgRE5BLiBTcGxpdCB0aGUgRE5BIGludG8gbm9ub3ZlcmxhcHBpbmcgcmVnaW9ucyBvZiBlcXVhbCBsZW5ndGggdG8gY29tcGFyZSB0aGUgbnVtYmVyIG9mIHBhbGluZG9tcmVzIGluIGFuIGludGVydmFsIHRvIHRoZSBudW1iZXIgb2YgdGhhdCB5b3Ugd291bGQgZXhwZWN0IGZyb20gdW5pZm9ybSByYW5kb20gc2NhdHRlci4gVGhlIGNvdW50cyBmb3Igc2hvcnRlciByZWdpb25zIHdpbGwgYmUgbW9yZSB2YXJpYWJsZSB0aGFuIHRob3NlIGZvciBsb2duZXIgcmVnaW9ucy4gQWxzbywgY29uc2lkZXIgY2xhc3NpZnlpbmcgdGhlIHJlZ2lvbnMgYWNjb3JkaW5nIHRvIHRoZSBudW1iZXIgb2YgY291bnRzLgpgYGB7cn0KayA8LSA1MAp0YWIgPC0gdGFibGUoY3V0KGxvY2F0aW9ucywgYnJlYWtzID0gc2VxKDAsIE4sIGxlbmd0aC5vdXQgPSBrKzEpLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKQpjb3VudHMub2JzIDwtIGFzLnZlY3Rvcih0YWIpCmEgPC0gdGFibGUoY3V0KGNvdW50cy5vYnMsIGJyZWFrcyA9IHNlcShtaW4oY291bnRzLm9icyksIG1heChjb3VudHMub2JzKSwgbGVuZ3RoLm91dCA9IGsrMSksIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpCgojIEhpc3RvZ3JhbSBvZiBjb3VudHMgb2YgcGFsaW5kcm9tZXMgaW4gb3JpZ2luYWwgZGF0YSBhbmQgcG9pc3NvbiBkaXN0cmlidXRpb24KaGlzdChjb3VudHMub2JzLCBicmVha3MgPSAxNSwgY29sID0gcmdiKDEsMCwwLDAuNSksIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJDb3VudHMgRGlzdHJpYnV0aW9uIENvbXBhcmlzb24gKDUwIFN1Yi1pbnRlcnZhbHMpIiwgeGxhYiA9ICJOdW1iZXIgb2YgUGFsaW5kcm9tZXMgU2l0ZXMgSW5zaWRlIGFuIEludGVydmFsIiwgeWxpbSA9IGMoMCwwLjIpKQpsaW5lcyhkZW5zaXR5KGNvdW50cy5vYnMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMSwwLDAsMC41KSkKUG9pcyA8LSBycG9pcyhuLCBsYW1iZGEgPSBtZWFuKGNvdW50cy5vYnMpKQpoaXN0KFBvaXMsIGJyZWFrcyA9IDE1LCBjb2wgPSByZ2IoMCwwLDEsMC41KSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBhZGQgPSBUUlVFKQpsaW5lcyhkZW5zaXR5KFBvaXMsIGFkanVzdCA9IDIpLCBjb2wgPSByZ2IoMCwwLDEsMC41KSkKbGVnZW5kKHggPSAxMiwgeSA9IDAuMTUsIGxlZ2VuZCA9IGMoInNhbXBsZSIsICJQb2lzc29uIiksIGx0eSA9IGMoMSwxKSwgY29sID0gYyhyZ2IoMSwwLDAsMC41KSwgcmdiKDAsMCwxLDAuNSkpKQoKIyBDaGktU3F1YXJlIFRlc3RpbmcKIyBDb25zdHJ1Y3QgcGFsaW5kcm9tZSBjb3VudCBudW1iZXIKcGFsaW5kcm9tZS5jb3VudCA8LSBjKCIwLDEsMiIsICIzIiwiNCIsIjUiLCI2IiwiNyIsIjgrIikKIyBDb25zdHJ1Y3Qgb2JzZXJ2ZWQgbnVtYmVyIG9mIGludGVydmFscwppbnRlcnZhbHMub2JzZXJ2ZWQgPC0gYyg4LCA5LCAxMywgMTAsIDgsIDgsIDUpIAojIENvbnN0cnVjdCBleHBlY3RlZCBudW1iZXIgb2YgaW50ZXJ2YWxzCmV4cGVjdGVkIDwtIGMoKQpsYW1iZGEgPC0gbi9rCmZvciAoaSBpbiBjKDA6MTcpKXsKICBleHBlY3QgPC0gayogZXhwKC1sYW1iZGEpKiBsYW1iZGEqKmkgL2ZhY3RvcmlhbChpKQogIGV4cGVjdGVkIDwtIGMoZXhwZWN0ZWQsIGV4cGVjdCkKfQpzdW0gPC0gMApmb3IgKGogaW4gYyg5OjE3KSl7CiAgc3VtIDwtIHN1bStleHBlY3RlZFtqXQp9CmludGVydmFscy5leHBlY3RlZCA8LSBjKGV4cGVjdGVkWzFdK2V4cGVjdGVkWzJdK2V4cGVjdGVkWzNdLGV4cGVjdGVkWzRdLGV4cGVjdGVkWzVdLGV4cGVjdGVkWzZdLGV4cGVjdGVkWzddLGV4cGVjdGVkWzhdLHN1bSkKCiMgQ3JlYXRlIGNvbnRpbmdlbmN5IHRhYmxlCmIgPC0gZGF0YS5mcmFtZShwYWxpbmRyb21lLmNvdW50LGludGVydmFscy5vYnNlcnZlZCxpbnRlcnZhbHMuZXhwZWN0ZWQpCmIKCmNoaV8yIDwtIHN1bSgoaW50ZXJ2YWxzLm9ic2VydmVkIC0gaW50ZXJ2YWxzLmV4cGVjdGVkKV4yL2ludGVydmFscy5leHBlY3RlZCkKY2hpMl9jb21wYXJlIDwtIHFjaGlzcShwID0gMC45NSwgZGYgPSA3KQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGYgPSA3LCBsb3dlci50YWlsID0gRkFMU0UpCnByaW50KGNhdCgiXG5XaGVuIGNvbmR1Y3RpbmcgY2hpX3NxdWFyZSBHb29kbmVzcyBvZiBmaXQgdGVzdCBjb21wYXJpbmcgbG9jYXRpb25zKGRpdmlkZWQgaW4gNTAwIHN1Yi1pbnRlcnZhbHMpIGFnYWluc3QgdW5pZm9ybSBkaXN0cmlidXRpb25cbiIpKQpwcmludChwYXN0ZSgiVGhlIHZhbHVlIG9mIGNoaV9zcXVhcmUgc3RhdGlzdGljIGlzIiwgY2hpXzIpKQpwcmludChwYXN0ZSgiVGhlIHBfdmFsdWUgaXMiLCBwX3ZhbHVlKSkKCgo9PT09PT09CmRpc3RhbmNlLnRyaXBsZXRzCmxvY2F0aW9ucwo+Pj4+Pj4+IDdjNmQ5MTE2MmU5NDIyNDhhNzJiNzM3NmUzYmE5NmEwY2JlZmI1MDAKPj4+Pj4+PiAyNTAzOTY2YzRlZmZiYTAyNzQwMzljMGNlYWYzMmY5YzRiYzRhOTBlCmBgYApHYW0gPC0gcmdhbW1hKG4tMiwgMiwgcmF0ZSA9IDIvbWVhbihkaXN0YW5jZS50cmlwbGV0cykpCiMjIFNjZW5hcmlvIDQ6IFRoZSBCaWdnZXN0IENsdXN0ZXIKRG9lcyB0aGUgaW50ZXJ2YWwgd2l0aCB0aGUgZ3JlYXRlc3QgbnVtYmVyIG9mIHBhbGluZHJvbWVzIGluZGljYXRlIGEgcG90ZW50aWFsIG9yaWdpbiBvZiByZXBsaWNhdGlvbj8gQmUgY2FyZWZ1bCBpbiBtYWtpbmcgeW91ciBpbnRlcnZhbHMsIGZvciBhbnkgc21hbGwsIGJ1dCBzaWduaWZpY2FudCBkZXZpYXRpb25zIGZyb20gcmFuZG9tIHNjYXR0ZXIsIHN1Y2ggYXMgYSB0aWdodCBjbHVzdGVyIG9mIGEgZmV3IHBhbGluZHJvbWVzLCBjb3VsZCBlYXNpbHkgZ28gdW5kZXRlY3RlZCBpZiB0aGUgcmVnaW9ucyBleGFtaW5lZCBhcmUgdG9vIGxhcmdlLiBBbHNvLCBpZiB0aGUgcmVnaW9ucyBhcmUgdG9vIHNtYWxsLCBhIGNsdXN0ZXIgb2YgcGFsaW5kcm9tZXMgbWF5IGJlIHNwbGl0IGJldHdlZW4gYWRqYWNlbnQgaW50ZXJhdmxzIGFuZCBub3QgYXBwZWFyIGFzIGEgaGlnaC1jb3VudCBpbnRlcnZhbC4KYGBge3J9CmZpbmFsIDwtIGFycmF5KGRpbT1jKDUwMCwxKSkKaW50ZXJ2YWxfbGVuZ3RoIDwtIGFycmF5KGRpbT1jKDUwMCwxKSkKbGFtZGEgPC0gYXJyYXkoZGltPWMoNTAwLDEpKQpmb3IgKGsgaW4gMjA6MTAwKXsKICB0YWIgPC0gdGFibGUoY3V0KGxvY2F0aW9ucywgYnJlYWtzPXNlcSgwLCBOLCBsZW5ndGgub3V0PWsrMSksIGluY2x1ZGUubG93ZXN0PVRSVUUpKQogIGhlYWQodGFiLDEwKQogIHRhYjwtYXMudmVjdG9yKHRhYikKICBsYW1kYVtrLF0gPC1zdW0odGFiKS9rCiAgdGhyZXNob2xkIDwtbWF4KHRhYikKICByZXN1bHQgPC0gMAogIGludGVydmFsX2xlbmd0aFtrLF0gPC0gTi9rCiAgZm9yIChpIGluIDA6KHRocmVzaG9sZC0xKSl7CiAgICByZXN1bHQgPC0gcmVzdWx0KygobGFtZGFba11eaSkqZXhwKC1sYW1kYVtrXSkvZmFjdG9yaWFsKGkpKQogIH0KICBmaW5hbFtrLF0gPC0gMS1yZXN1bHReawp9CnJlc3VsdCA8LSBkYXRhLmZyYW1lKGxhbWRhLGludGVydmFsX2xlbmd0aCxmaW5hbCkKCiMgRGlzcGxheSBUYWJsZSBjb250YWluaW5nIHRoZSBwcm9iYWJpbGl0eSBvZiBhIFBvaXNzb24gRGlzdHJpYnV0aW9uIGhhdmluZyBlIGdyZWF0ZXN0IG51bWJlciBvZiBoaXRzIGF0IGxlYXN0IGsgZm9yIGVhY2ggc3ViLWludGVydmFsIGRpdmlzaW9ucwpyZXN1bHRbYygyMDoxMDApLF0KYGBgCgoKCiMjIEFkZGl0aW9uYWwgU2NlbmFyaW86IEhJViBhbmQgQWdlClRPRE8gRGVzY3JpcHRpb24KYGBge3J9CiMgQ2xlYW4gb3V0ICd1bmtub3duJyBkYXRhIGFuZCBjb252ZXJ0IGZhY3RvciB0byBudW1lcmljYWwgdmFsdWVzCmhlYWx0aCA8LSB0cmFuc2Zvcm0oaGVhbHRoLCBhZ2VfeXJzPWFzLm51bWVyaWMoYWdlX3lycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaXY9YXMuY2hhcmFjdGVyKGhpdikpCmhlYWx0aC5pbmQgPC0gd2hpY2goaGVhbHRoJGhpdiAhPSAndW5rbm93bicpCmhlYWx0aCA8LSBoZWFsdGhbaGVhbHRoLmluZCxdCgojIFRvdGFsIG51bWJlciBvZiBwZW9wbGUgdGhhdCBoYXZlIGhpdgpwb3B1bGF0aW9uPW5yb3coaGVhbHRoKQpwb3BfaGl2IDwtIG5yb3coaGVhbHRoW3doaWNoKGhlYWx0aCRoaXY9PSdwb3NpdGl2ZScpLF0pCgojIFNwbGl0IHRoZSBhZ2UgaW50byBmb3VyIGdyb3VwcwojIDAtMjAKYWdlX2ZpcnN0IDwtIGhlYWx0aCRhZ2VfeXJzW3doaWNoKGhlYWx0aCRhZ2VfeXJzPDIxKV0KYWdlX3Byb3BvcnRpb25fZmlyc3QgPC0gbGVuZ3RoKGFnZV9maXJzdCkvcG9wdWxhdGlvbgpoaXZfcHJvcG9ydGlvbl9maXJzdDwtIG5yb3coaGVhbHRoW3doaWNoKChoZWFsdGgkaGl2PT0gJ3Bvc2l0aXZlJykgJiAoaGVhbHRoJGFnZV95cnMgPDIxKSksXSkvcG9wX2hpdgoKIyAyMS00MAphZ2Vfc2Vjb25kPC1oZWFsdGgkYWdlX3lyc1t3aGljaChoZWFsdGgkYWdlX3lycz4yMCAmIGhlYWx0aFsnYWdlX3lycyddPDQxKV0KYWdlX3Byb3BvcnRpb25fc2Vjb25kIDwtIGxlbmd0aChhZ2Vfc2Vjb25kKS9wb3B1bGF0aW9uCmhpdl9wcm9wb3J0aW9uX3NlY29uZDwtbnJvdyhoZWFsdGhbd2hpY2goaGVhbHRoJGFnZV95cnM+MjAgJmhlYWx0aCRhZ2VfeXJzPDQxICYgaGVhbHRoJGhpdj09J3Bvc2l0aXZlJyksXSkvcG9wX2hpdgoKIyA0MS02MAphZ2VfdGhpcmQ8LWhlYWx0aCRhZ2VfeXJzW3doaWNoKGhlYWx0aFsnYWdlX3lycyddPjQwICYgaGVhbHRoWydhZ2VfeXJzJ108NjEpXQphZ2VfcHJvcG9ydGlvbl90aGlyZCA8LSBsZW5ndGgoYWdlX3RoaXJkKS9wb3B1bGF0aW9uCmhpdl9wcm9wb3J0aW9uX3RoaXJkPC1ucm93KGhlYWx0aFt3aGljaChoZWFsdGgkYWdlX3lycz40MCAmIGhlYWx0aCRhZ2VfeXJzPDYxICZoZWFsdGgkaGl2PT0ncG9zaXRpdmUnKSxdKS9wb3BfaGl2CgojIDYxKwphZ2VfbGFzdDwtaGVhbHRoJGFnZV95cnNbd2hpY2goaGVhbHRoWydhZ2VfeXJzJ10+NjApXQphZ2VfcHJvcG9ydGlvbl9sYXN0IDwtIGxlbmd0aChhZ2VfbGFzdCkvcG9wdWxhdGlvbgpoaXZfcHJvcG9ydGlvbl9sYXN0PC1ucm93KGhlYWx0aFt3aGljaChoZWFsdGgkYWdlX3lycz42MCAmIGhlYWx0aCRoaXY9PSdwb3NpdGl2ZScpLF0pL3BvcF9oaXYKCiMgRXhwZWN0ZWQgRGF0YQpwb3B1bGF0aW9uX2Rpc3QgPC1jKGFnZV9wcm9wb3J0aW9uX2ZpcnN0LGFnZV9wcm9wb3J0aW9uX3NlY29uZCxhZ2VfcHJvcG9ydGlvbl90aGlyZCxhZ2VfcHJvcG9ydGlvbl9sYXN0KQojIE9ic2VydmVkIERhdGEKaGl2X2Rpc3Q8LWMoaGl2X3Byb3BvcnRpb25fZmlyc3QsaGl2X3Byb3BvcnRpb25fc2Vjb25kLGhpdl9wcm9wb3J0aW9uX3RoaXJkLGhpdl9wcm9wb3J0aW9uX2xhc3QpCgojIEdvb2RuZXNzLWZpdHRlc3QKY2hpXzIgPC0gc3VtKChoaXZfZGlzdCAtIHBvcHVsYXRpb25fZGlzdCleMi9wb3B1bGF0aW9uX2Rpc3QpCmNoaTJfY29tcGFyZSA8LSBxY2hpc3EocD0wLjk1LCBkZj0zKQpwX3ZhbHVlIDwtIHBjaGlzcShjaGlfMiwgZGY9MywgbG93ZXIudGFpbD1GQUxTRSkKcHJpbnQocGFzdGUoJ1RoZSBwX3ZhbHVlIG9mIEdvb2RuZXNzIG9mIEZpdCBUZXN0IGlzJyxwX3ZhbHVlKSkKCiNWaXN1YWxpemF0aW9uClJlc2lkdWFscyA8LSAoaGl2X2Rpc3QgLSBwb3B1bGF0aW9uX2Rpc3QpIC8gc3FydChwb3B1bGF0aW9uX2Rpc3QpCnBsb3QoUmVzaWR1YWxzLCB0eXBlPSdoJywgeWxhYj0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWI9J1Byb3BvcnRpb24gb2YgUG9zaXRpdmUgSElWJywgbWFpbj0nUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWwgZm9yIEFnZSBhbmQgSElWIFBvc2l0aXZlJykKYGBgCgpOdWxsIEh5cG90aGVzaXM6IFRoZSBwcm9wb3J0aW9uIG9mIGFnZSBpbiB0aGUgcG9wdWxhdGlvbiBpcyB1bnJlbGF0ZWQgd2l0aCB0aGUgcHJvcG9ydGlvbiBvZiBwZW9wbGUgaGF2aW5nIGhpdi4oQWdlIGlzIG5vdCBhbiBpbmZsdWVuY2luZyBmYWN0b3IgZm9yIEhJViB0ZXN0aW5nIHBvc2l0aXZlKQpTaW5jZSBwLXZhbHVlIG9mIHRoaXMgY2hpLXNxdWFyZSBnb29kbmVzcyBvZiBmaXQgdGVzdCBpcyBjbG9zZSB0byAxLCB3ZSBzZWUgdGhhdCBkZXZpYXRpb25zIGFzIGxhcmdlIGFzIG91cnMgKG9yIGxhcmdlcikgYXJlIHZlcnkgbGlrZWx5LiBJbiBhZGRpdGlvbiwgaGF2aW5nIHZhbHVlcyBvZiB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFsIGxlc3MgdGhhbiAzIHN1Z2dlc3RzIHRoYXQgaXQgaXMgYSBnb29kIGZpdCBvZiB0aGUgYWdlIGRpc3RyaWJ1dGlvbiB0byBlc3RpbWF0ZSB0aGUgcGVvcGxlIHRlc3RpbmcgcG9zaXRpdmUgb24gaGl2LiBIZW5jZSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgYW5kIGNvbmNsdWRlIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwcm9wb3J0aW9uIG9mIGFnZSBtYXRjaGVzIHdpdGggdGhlIHRoZSBkaXN0cmlidXRpb24gb2YgcGVvcGxlIHRlc3RpbmcgcG9zaXRpdmUgb24gSElWLg==